/**********************************************************************/
/**  Copyright (c) ECC labs. 2001-2002. All Rights Reserved.		 **/
/**********************************************************************/
/*
	binspace.cpp
	Mark Papazyan

*/


#include "binspace.h"

CBinSpace::CBinSpace(t_len k, t_len n, int flag, int base)
	:CBinMatrix(k, n, flag, base){}


CBinSpace::CBinSpace(const CBinSpace& t)
{
	row=new CBinWord[k=t.k];
	col=new CBinWord[n=t.n];

	flag=t.flag;
	base=t.base;

	for(t_cnt i=0; i<k; i++)
	{
		row[i].num=t.row[i].num;
		row[i].n=t.n;
	}
	
	for(t_cnt ii=0; ii<n; ii++)
		col[ii].n=t.k;

	if(t.flag&HAVE_COL)//checks if cols were made
		for(t_cnt j=0; j<n; j++)
			col[j].num=t.col[j].num;

	if(t.flag & PERM)
	{
		/*series=new t_tab[n];

		for(t_cnt ii=0; ii<n ;ii++)
			series[ii]=char(ii);*/
		dat.s = new int[n] ;
		dat.flag = new long[n];
		pos = pos1 = 0 ;
		for ( t_cnt i=0; i<n; i++ ) {
			dat.s[i]=i ;
			dat.flag[i]=I<<i;
		}
	}
}

CBinSpace CBinSpace::operator&&(CBinSpace& a)
{
	t_cnt i=0;
	CBinSpace c(k+a.k, n);
	for(i=0; i<k; i++)
		c.row[i].num=row[i].num;
	for(t_cnt j=0; j<a.k; j++)
		c.row[i+j].num=a.row[j].num;

	CBinWord t=c.gaus();
	c.k=t.wt();
	return c;
}

CBinSpace CBinSpace::operator&=(CBinSpace& a)
{

	*this=*this&&a;
	return *(this);
}

/*
void CBinSpace::operator|=(CBinSpace& a)
{
	a.row2col();
	row2col();
	CBinSpace C(n, k+a.k);

	for(t_cnt i=0; i<n; i++)
		C.row[i].num=(col[i].num<<a.k)^a.col[i].num;

	CBinWord t=C.col_gaus();

	C.n=t.wt();

	delete[] row;
	if(flag&COL)
		delete[] col;
	
	k=C.n;
	n=C.k;
	flag=ROW;
	row=new CBinWord[k];

	for(t_cnt j=0; j<k; j++)
		row[j]=C.col[j];
}
*/
CBinSpace CBinSpace::operator ||(CBinSpace a)
{
	CBinSpace ret=*this;
	ret.convert();
	a.convert();
	ret=(ret&&a);
    ret.convert();
	return ret;
}

CBinSpace CBinSpace::operator|=(CBinSpace a)
{
   convert();
   a.convert();
   *this=(*this&&a);
   convert();
   return *(this);
}

ostream& operator<<(ostream& out, CBinSpace& a)
{
	return operator<<(out, (CBinMatrix&)a);
}



istream& operator>>(istream& in, CBinSpace& a)
{
	return operator>>(in, (CBinMatrix&)a);
}



CBinSpace& CBinSpace::operator =(const CBinSpace& t)
{
	if(this!=&t)
	{
		delete[] row;
		delete[] col;
		
		if(flag& PERM){
			delete[] dat.flag;
			delete[] dat.s;
		}

		row=new CBinWord[k=t.k];
		col=new CBinWord[n=t.n];

		flag=t.flag;
		base=t.base;

		for(t_cnt i=0; i<k; i++)
		{
			row[i].num=t.row[i].num;
			row[i].n=n;
		}

		for(t_cnt ii=0; ii<n; ii++)
			col[ii].n=k;

		if(t.flag & HAVE_COL)//checks if cols were made
			for(t_cnt j=0; j<n; j++)
				col[j].num=t.col[j].num;

		if(t.flag & PERM)
		{
			dat.s = new int[n] ;
			dat.flag = new long[n];
			pos = pos1 = 0 ;
			for ( t_cnt i=0; i<n; i++ ) {
				dat.s[i]=t.dat.s[i] ;
				dat.flag[i]=t.dat.flag[i] ;
			}
		}

	}

	return *this;
}


void union_space(CBinSpace&c, CBinSpace& b, CBinSpace& a)
{
	t_cnt i=0;
	for(i=0; i<b.k; i++)
		c.row[i].num=b.row[i].num;
	for(t_cnt j=0; j<a.k; j++)
		c.row[i+j].num=a.row[j].num;

	CBinWord t=c.gaus();
	c.k=t.wt();
}

void intersect_space(CBinSpace&c, CBinSpace b, CBinSpace a)
{
   b.convert();
   a.convert();
   c=b&&a;
   c.convert();
}

void CBinSpace::convert()
{
	if(n==k)
		return;
	CBinSpace Res(n-k,n);

	CBinWord check(n,(t_src)0);	//two vectors dim=n: vector of primary values
	CBinWord uncheck(n,(t_src)0);	//vector of free values
	CBinWord temp(n,(t_src)0);	//here we'll count our results
	CBinWord pos(k, (t_src)0);	//vector that indicates those rows where vector of primary values are
	CBinWord some(n, (t_src)0);
	t_len s;

	check=gaus();
	uncheck.num=~check.num;	//switching vector of free values

	
	t_len h=0;
	s=0;
	
	for(t_cnt i=0; i<n-k; i++)
	{
		while(!((uncheck.num>>s)&I))s++;	//finding first 1 in a vector of free values
		temp.num=check.num^(I<<s);	//switching on free value 1 position
		s++;

		for(t_cnt f=k-1; f>=0; f--)
		{
				while(!(check.num>>h&I))h++;	//finding 1 in a vector of primary values
			
				some.num=row[f].num&temp.num;
		
				temp.num^=((some.wt()%2))<<h;	//switch on position from primary	
				
				h++;
		}

		Res.row[i].num=temp.num;
		h=0;
	}
	
	*this=Res;


	set_h();

}

void CBinSpace::set_h()
{
	flag^=IS_H^IS_G;
}


void CBinSpace::set_g()
{
	flag^=IS_H^IS_G;
}
